﻿using System;
using System.Globalization;
using System.Windows.Forms;
using NEH_SA.Logika;
using System.Collections.Generic;
using NEH_SA.Model;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;

namespace NEH_SA.UI
{
    public partial class Form1 : Form
    {
        private List<Rozwiązanie> _rozwiązania;
        private Mutex _mutex;
        public List<Problem> ProblemyLista { get; set; }

        public CancellationTokenSource CancellationTokenSourceSa { get; set; }
        public CancellationTokenSource CancellationTokenSourceAco { get; set; }
        public CancellationTokenSource CancellationTokenSourceTabu { get; set; }
        public CancellationTokenSource CancellationTokenSourceGa { get; set; }

        public List<Rozwiązanie> Rozwiązania
        {
            get { return _rozwiązania ?? (_rozwiązania = new List<Rozwiązanie>()); }
        }

        public Form1()
        {
            var a = Task.Factory.StartNew(Action);
            var b = Task.Factory.StartNew(Action);

            InitializeComponent();
            DataTransition.AddProblem += AddProblemToListbox;
            DataTransition.RemoveProblem += RemoveProblemFromListbox;
            DataTransition.Log += Log;
            DataTransition.LiczbaProblemówChange += LiczbaProblemówChange;
            DataTransition.VisibilityChange += ShowHideProgressBar;
            DataTransition.PostępChange += PostępChange;
            _mutex = new Mutex();
        }

        private void Action()
        {
           
            while (true)
            {
                var a = "d";
                a = "s";
            }
        }

        private void PostępChange()
        {
            Invoke((MethodInvoker)(() =>
                                       {

                                           progressBar1.Value++;
                                       }));
        }

        private void ShowHideProgressBar(bool value)
        {
            Invoke((MethodInvoker)(() =>
                                        {
                                            progressBar1.Visible = value;
                                            progressBar1.Value = 0;
                                        }));

        }

        private void LiczbaProblemówChange(int number)
        {
            Invoke((MethodInvoker)(() =>
                                       {
                                           textBox1.Text = number.ToString(CultureInfo.InvariantCulture);
                                           progressBar1.Maximum = number;
                                       }));
        }

        private void Log(string msg)
        {
            Invoke((MethodInvoker)(() =>
            {
                richTextBox1.AppendText(msg + Environment.NewLine);
                richTextBox1.ScrollToCaret();
            }));
        }

        private void RemoveProblemFromListbox(string msg)
        {
            Invoke((MethodInvoker)(() => listBox1.Items.Remove(msg)));
        }

        private void AddProblemToListbox(string msg)
        {
            Invoke((MethodInvoker)(() => listBox1.Items.Add(msg)));
        }

        private void ButtonWczytajClick(object sender, System.EventArgs e)
        {
            var openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
                Task<List<Problem>>.Factory.StartNew(() => Logika.Program.WczytajDane(openFileDialog1.FileName))
                    .ContinueWith(task => ProblemyLista = task.Result, TaskContinuationOptions.OnlyOnRanToCompletion)
                    .ContinueWith(ActivateAlgorithmButtons, TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        private void ActivateAlgorithmButtons(Task task)
        {
            Invoke((MethodInvoker)(() =>
                                        {
                                            buttonObliczNEH.Enabled = true;
                                            buttonObliczSA.Enabled = true;
                                            buttonGA.Enabled = true;
                                            buttonTABU.Enabled = true;
                                            buttonACO.Enabled = true;
                                            button1.Enabled = true;

                                        }));

        }
        private void DeactivateAlgorithmButtons(bool act)
        {
            Invoke((MethodInvoker)(() =>
            {
                buttonObliczNEH.Enabled = act;
                buttonObliczSA.Enabled = act;
                buttonGA.Enabled = act;
                buttonTABU.Enabled = act;
                buttonACO.Enabled = act;
                button1.Enabled = act;

            }));

        }

        private void ButtonZapiszClick(object sender, System.EventArgs e)
        {
            var saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Logika.Program.ZapiszRozwiązanie(Rozwiązania, saveFileDialog1.FileName);
            }
        }

        private void ButtonObliczNehClick(object sender, System.EventArgs e)
        {
            //Usuń dotychczasowe rozwiązania
            _rozwiązania = Rozwiązania.Where(rozwiązanie => rozwiązanie.TypRozwiązania != Algorytm.Neh).ToList();
            Task<IEnumerable<Rozwiązanie>>.Factory.StartNew(() =>
                                                                {
                                                                    _mutex.WaitOne();
                                                                    var result = Logika.Program.ObliczNehem(ProblemyLista);
                                                                    _mutex.ReleaseMutex();
                                                                    return result;
                                                                }, TaskCreationOptions.LongRunning)
                                           .ContinueWith(task => _rozwiązania.AddRange(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
                                           .ContinueWith(ActivateSaveButton, TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        private void ButtonObliczSaClick(object sender, System.EventArgs e)
        {
            //Usuń dotychczasowe rozwiązania
            _rozwiązania = Rozwiązania.Where(rozwiązanie => rozwiązanie.TypRozwiązania != Algorytm.Sa).ToList();

            CancellationTokenSourceSa = new CancellationTokenSource();
            buttonCancel.Enabled = true;
            DeactivateAlgorithmButtons(false);
            Task<List<Rozwiązanie>>.Factory.StartNew(() =>
                                                         {
                                                             _mutex.WaitOne();
                                                             var result = Logika.Program.ObliczSa(ProblemyLista, CancellationTokenSourceSa.Token);
                                                             _mutex.ReleaseMutex();
                                                             return result;

                                                         }, CancellationTokenSourceSa.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                                   .ContinueWith(task => _rozwiązania.AddRange(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
                                   .ContinueWith(ActivateSaveButton, TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        private void ActivateSaveButton(Task task)
        {
            Invoke((MethodInvoker)(() =>
                                       {
                                           buttonZapisz.Enabled = true;
                                           DeactivateAlgorithmButtons(true);

                                       }));
        }

        private void ButtonCancelClick(object sender, EventArgs e)
        {

            if (CancellationTokenSourceSa != null && CancellationTokenSourceSa.Token.CanBeCanceled)
            {
                CancellationTokenSourceSa.Cancel();
            }
            if (CancellationTokenSourceGa != null && CancellationTokenSourceGa.Token.CanBeCanceled)
            {
                CancellationTokenSourceGa.Cancel();
            }
            if (CancellationTokenSourceTabu != null && CancellationTokenSourceTabu.Token.CanBeCanceled)
            {
                CancellationTokenSourceTabu.Cancel();
            }
            if (CancellationTokenSourceAco != null && CancellationTokenSourceAco.Token.CanBeCanceled)
            {
                CancellationTokenSourceAco.Cancel();
            }
            DeactivateAlgorithmButtons(true);
            buttonCancel.Enabled = false;
        }

        private void ButtonAcoClick(object sender, EventArgs e)
        {
            _rozwiązania = Rozwiązania.Where(rozwiązanie => rozwiązanie.TypRozwiązania != Algorytm.Aco).ToList();
            CancellationTokenSourceAco = new CancellationTokenSource();
            buttonCancel.Enabled = true;
            DeactivateAlgorithmButtons(false);
            Task<IEnumerable<Rozwiązanie>>.Factory.StartNew(() =>
                                                                {
                                                                    _mutex.WaitOne();
                                                                    var result = Logika.Program.ObliczAco(ProblemyLista, CancellationTokenSourceAco.Token);
                                                                    _mutex.ReleaseMutex();
                                                                    return result;
                                                                }
                , CancellationTokenSourceAco.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                       .ContinueWith(task => _rozwiązania.AddRange(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
                       .ContinueWith(ActivateSaveButton, TaskContinuationOptions.OnlyOnRanToCompletion);


        }

        private void ButtonTabuClick(object sender, EventArgs e)
        {
            _rozwiązania = Rozwiązania.Where(rozwiązanie => rozwiązanie.TypRozwiązania != Algorytm.Tabu).ToList();
            CancellationTokenSourceTabu = new CancellationTokenSource();
            buttonCancel.Enabled = true;
            DeactivateAlgorithmButtons(false);
            Task<IEnumerable<Rozwiązanie>>.Factory.StartNew(() =>
                                                                {
                                                                    _mutex.WaitOne();
                                                                    var result = Logika.Program.ObliczTabu(ProblemyLista, CancellationTokenSourceTabu.Token);
                                                                    _mutex.ReleaseMutex();
                                                                    return result;

                                                                }, CancellationTokenSourceTabu.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                       .ContinueWith(task => _rozwiązania.AddRange(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
                       .ContinueWith(ActivateSaveButton, TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        private void ButtonGaClick(object sender, EventArgs e)
        {

            _rozwiązania = Rozwiązania.Where(rozwiązanie => rozwiązanie.TypRozwiązania != Algorytm.Ga).ToList();
            CancellationTokenSourceGa = new CancellationTokenSource();
            buttonCancel.Enabled = true;
            DeactivateAlgorithmButtons(false);
            Task<IEnumerable<Rozwiązanie>>.Factory.StartNew(() =>
                                                                {
                                                                    _mutex.WaitOne();
                                                                    var result = Logika.Program.ObliczGA(ProblemyLista, CancellationTokenSourceGa.Token);
                                                                    _mutex.ReleaseMutex();
                                                                    return result;

                                                                }, CancellationTokenSourceGa.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                       .ContinueWith(task => _rozwiązania.AddRange(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
                       .ContinueWith(ActivateSaveButton, TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        private void Button1Click(object sender, EventArgs e)
        {
            ButtonObliczNehClick(sender, e);
            ButtonAcoClick(sender, e);
            ButtonTabuClick(sender, e);
            ButtonGaClick(sender, e);
            ButtonObliczSaClick(sender, e);
        }


    }
}
